﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using UCS.XNA.Draughts.Boards;
using UCS.XNA.Draughts.Pieces;
using UCS.XNA.Utils.Physics;

namespace UCS.XNA.Draughts.People
{
    public class Player
    {
        #region Attributes and Properties

        private PieceColor _color;
        public PieceColor Color
        {
            get { return this._color; }
            set { this._color = value; }
        }

        private bool _isComputerControlled = false;
        public bool IsComputerControlled
        {
            get { return _isComputerControlled; }
        }

        private Board _board;
        public Board Board
        {
            get { return _board; }
            set { _board = value; }
        }

        #endregion

        #region Private Members

        private MouseState _lastMouseState;
        private BoardPosition _lastMousePosition;
        private Vector2? _mouseDragOffset;
        private Piece _draggingPiece;

        #endregion

        #region Events

        public event EventHandler<CancelEventArgs> PickingPieceUp;
        public event EventHandler<PuttingPieceDownEventArgs> PuttingPieceDown;
        public event EventHandler<PieceMovedEventArgs> PieceMoved;
        public event EventHandler<PieceMovementCompletedEventArgs> PieceMovementCompleted;

        #endregion

        #region Constructors

        public Player(PieceColor color, bool isComputerControlled)
        {
            _color = color;
            _isComputerControlled = isComputerControlled;
        }

        #endregion

        #region Public Methods

        public void Update(GameTime gameTime)
        {
            this.CheckAndExecuteMouseDrag();

            this._lastMouseState = Mouse.GetState();
        }

        #endregion

        #region Private Methods

        private void CheckAndExecuteMouseDrag()
        {
            MouseState mouseState = Mouse.GetState();

            if (mouseState.LeftButton == ButtonState.Pressed)
            {
                if (_lastMouseState.LeftButton == ButtonState.Released && !this._isComputerControlled)
                {
                    IEnumerable<Piece> pieces = _board.GetPieces(_color);

                    foreach (Piece piece in pieces)
                    {
                        if (CollisionDetector.TestFullCollision(piece, new Vector2(mouseState.X, mouseState.Y)))
                        {
                            CancelEventArgs eventArgs = new CancelEventArgs();
                            if (this.PickingPieceUp != null)
                                this.PickingPieceUp(piece, eventArgs);

                            if (!eventArgs.Cancel)
                            {
                                _mouseDragOffset = new Vector2(mouseState.X - piece.Position.X, mouseState.Y - piece.Position.Y);
                                _draggingPiece = piece;
                                piece.IsBeingDragged = true;
                                _lastMousePosition = piece.BoardPosition;
                            }

                            break;
                        }
                    }
                }
            }
            else if (this._mouseDragOffset.HasValue)
            {
                this._mouseDragOffset = null;
                if (this.PuttingPieceDown != null)
                {
                    int j = (mouseState.X + 2) / 58;
                    int i = (mouseState.Y + 2) / 58;

                    var boardPosition = new BoardPosition(i, j);
                    var e = new PuttingPieceDownEventArgs(_draggingPiece, boardPosition);
                    this.PuttingPieceDown(this, e);

                    if (!e.Cancel)
                        this.ApplyMovement(_draggingPiece, _draggingPiece.GetMovement(boardPosition));

                    _draggingPiece.IsBeingDragged = false;
                    _draggingPiece = null;
                }
            }

            if (this._mouseDragOffset.HasValue)
            {
                _draggingPiece.Position = new Vector2(mouseState.X, mouseState.Y) - this._mouseDragOffset.GetValueOrDefault();
                int j = (mouseState.X + 2) / 58;
                int i = (mouseState.Y + 2) / 58;

                var boardPosition = new BoardPosition(i, j);

                if (this.PieceMoved != null && !_lastMousePosition.Equals(boardPosition))
                {
                    this.PieceMoved(_draggingPiece, new PieceMovedEventArgs(_lastMousePosition, boardPosition));
                    _lastMousePosition = boardPosition;
                }
            }
        }

        public void ApplyMovement(Piece piece, PieceMovement movement)
        {
            if (movement == null)
                throw new InvalidOperationException("Movimentação Inválida!");

            var oldSquare = this._board[piece.BoardPosition];
            var newSquare = this._board[piece.BoardPosition + movement.BoardMovement];

            oldSquare.Piece = null;
            newSquare.Piece = piece;

            if (movement.JumpPosition != null)
            {
                BoardPosition killPosition = oldSquare.BoardPosition + movement.JumpPosition;
                this._board[killPosition].Piece = null;
            }

            if (piece is CommonPiece && ((piece.BoardPosition.I == 7 && piece.Color == PieceColor.Black) ||
                                         (piece.BoardPosition.I == 0 && piece.Color == PieceColor.White)))
            {
                newSquare.Piece = new QueenPiece(piece.Color, piece.BoardPosition);
                newSquare.Piece.InitializeTextures();
            }

            if (this.PieceMovementCompleted != null)
                this.PieceMovementCompleted(this, new PieceMovementCompletedEventArgs(piece, movement));
        }

        #endregion
    }
}
